using System;
using System.Collections;
using System.Text;
using System.Web;

using QuoteAdvantage.CrmSdk;

namespace QuoteAdvantage
{
	/// <summary>
	/// Wrapper class for Microsoft CRM quotedetail object
	/// </summary>
	public class QuoteDetail : CrmClass
	{
      private Quote     m_objQuote = null;  // Parent quote that owns this item
      private bool      m_bAllowDiscounting;
      private string    m_strConfigRuleFileName = "";  // Not tracked by database.
      private string    m_strCategoryId;
      private Guid      m_guidConfigParentId;
      private decimal   m_nExtendedAmount;
      private int       m_nLineItemNumber;
      private decimal   m_nManualDiscountAmount;
      private string    m_strName;
      private Guid      m_guidQuoteId;
      private Guid      m_guidQuoteDetailId;
      private decimal   m_nQuantity;
      private Guid      m_guidProductId;
      private decimal   m_nPricePerUnit;
      private string    m_strProductDescription;
      private string    m_strProductNumber;
      private int nProductTypeCode;  // Not tracked by database
      private string    m_strShipTo_Fax;
      private string    m_strShipTo_Line3;
      private Guid      m_guidUnitOfMeasureId;
      private string    m_strProductCustomField1;
      private string    m_strProductCustomField2;
      private decimal   m_nPercentDiscount;
      private decimal   m_nPercentMarkup;

		public QuoteDetail()
		{
		   	
		}

      public bool AllowDiscounting
      {
         get { return m_bAllowDiscounting; }
         set { m_bAllowDiscounting = value; }
      }     
    
      public string CategoryId
      {
         get 
         { 
            return m_strCategoryId;
         }
         set 
         { 
            m_strCategoryId = value;
         }

      }
            
      public Guid ConfigParentId
      {
         get 
         { 
            return m_guidConfigParentId;
         }
         set 
         { 
            m_guidConfigParentId = value;
         }
      }

      public string ConfigRuleFileName
      {
         get { return m_strConfigRuleFileName;}
         set { m_strConfigRuleFileName = value;}
      }

      public string ProductCustomField1
      {
         get { return m_strProductCustomField1;}
         set { m_strProductCustomField1 = value;}
      }

      public string ProductCustomField2
      {
         get { return m_strProductCustomField2;}
         set { m_strProductCustomField2 = value;}
      }       

      public decimal ExtendedAmount
      {
         get { return m_nExtendedAmount;}
         set { m_nExtendedAmount = value;}
      }

      public decimal PercentDiscount
      {
         get { return m_nPercentDiscount;}
         set { m_nPercentDiscount = value;}
      }

      public decimal PercentMarkup
      {
         get { return m_nPercentMarkup;}
         set { m_nPercentMarkup = value;}
      }

      public int LineItemNumber
      {
         get { return m_nLineItemNumber;}
         set { m_nLineItemNumber = value;}
      }

      public Decimal ManualDiscountAmount
      {
         get { return m_nManualDiscountAmount;}
         set { m_nManualDiscountAmount = value;}
      }

      public string Name
      {
         get { return m_strName;}
         set { m_strName = value;}
      }

      public Quote QuoteOwner
      {
         get { return m_objQuote;}
         set { m_objQuote = value;}
      }

      public Guid QuoteId
      {
         get { return m_guidQuoteId;}
         set { m_guidQuoteId = value;}
      }
      
      public Guid QuoteDetailId
      {
         get { return m_guidQuoteDetailId;}
         set { m_guidQuoteDetailId = value;}
      }

      public Decimal Quantity
      {
         get { return m_nQuantity;}
         set { m_nQuantity = value;}
      }

      public Decimal PricePerUnit
      {
         get { return m_nPricePerUnit;}
         set { m_nPricePerUnit = value;}
      }
      
      public string ProductDescription
      {
         get { return m_strProductDescription;}
         set { m_strProductDescription = value;}
      }

      public Guid ProductId
      {
         get { return m_guidProductId;}
         set { m_guidProductId = value;}
      }
      
      public string ProductNumber
      {
         get { return m_strProductNumber;}
         set { m_strProductNumber = value;}
      }

      // Not tracked by the database
      //     Flat Fees
      //     Miscellaneous Charges
      //     Sales Inventory
      // 3 = Services
      public int ProductTypeCode
      {
         get { return nProductTypeCode;}
         set { nProductTypeCode = value;}
      }  
      
      public string ShipToFax
      {
         get { return m_strShipTo_Fax;}
         set { m_strShipTo_Fax = value;}
      }
      
      public string ShipToLine3
      {
         get { return m_strShipTo_Line3;}
         set { m_strShipTo_Line3 = value;}
      }

      public Guid UnitOfMeasureId
      {
         get { return m_guidUnitOfMeasureId;}
         set { m_guidUnitOfMeasureId = value;}
      }

      
      // Adjust the fixed manual discount to a match a percentage based value
      // 1 = 100%
      // 0.5 = 50%
      public void ApplyPercentageMultiplier(decimal nMultiplier)
      {
         this.ManualDiscountAmount = 0;
   //     decimal nStartingPrice = CalculatePrice();
         decimal nStartingPrice = CalculatePriceForDiscounting();
         decimal nTargetPrice = nStartingPrice * nMultiplier;

         this.ManualDiscountAmount = nStartingPrice - nTargetPrice;
      }
      

      public void RefreshMultiplier()
      {
         // Multiplier = (100 - Discount + Multiplier) / 100
         decimal nNewMultiplier = (100 - this.PercentDiscount + this.PercentMarkup) / 100;
         this.ApplyPercentageMultiplier(nNewMultiplier);
      }

      public decimal CalculatePrice()
      {
         decimal     nPrice = this.PricePerUnit * this.Quantity;   
         ArrayList   objChildItems = this.GetChildItemList();

         foreach (QuoteDetail objItem in objChildItems)
         {
            decimal nChildPrice = objItem.CalculatePrice();  // Item price includes deeply nested children
            nChildPrice = nChildPrice - objItem.ManualDiscountAmount;
            nPrice += nChildPrice;   
         }

         nPrice = nPrice - this.ManualDiscountAmount;

         return nPrice;
      }  


      // Calculate the price (excluding linked items)
      public decimal CalculatePriceForDiscounting()
      {
         decimal     nPrice = this.PricePerUnit * this.Quantity;   
         ArrayList   objChildItems = this.GetChildItemList();

         foreach (QuoteDetail objItem in objChildItems)
         {
            decimal nChildPrice = objItem.CalculatePriceForDiscounting();  // Item price includes deeply nested children
            
            // Need to skip linked items
            if (objItem.CategoryId.IndexOf("LinkedItem For") == -1)
            {
               // This is not a linked item
               nChildPrice = nChildPrice - objItem.ManualDiscountAmount;
               nPrice += nChildPrice;   
            }         
         }

         nPrice = nPrice - this.ManualDiscountAmount;

         return nPrice;
      }  
    
      public decimal ConvertFixedDiscountToPercentage()
      {
         decimal nPercentageDiscount = 0;
         decimal nManualDiscountAmount = this.ManualDiscountAmount;  
         decimal nTargetPrice = CalculatePrice();

         this.ManualDiscountAmount = 0;  // Temporarily remove discount
         decimal nStartingPrice = CalculatePrice();

         if (nStartingPrice != 0)
         {
            nPercentageDiscount = nTargetPrice / nStartingPrice;
            nPercentageDiscount = Math.Round(nPercentageDiscount, 2);
         }

         this.ManualDiscountAmount = nManualDiscountAmount; // Restore discount

         return nPercentageDiscount;
      }
  
      // Return all of the child items of this QuoteDetail
      public ArrayList GetChildItemList()
      {
         ArrayList   objResultList = new ArrayList(10);

         foreach (QuoteDetail item in this.QuoteOwner.LineItems)
         {
            if (item.ConfigParentId == this.QuoteDetailId)
            {
               objResultList.Add(item);
            }
         }        

         return objResultList;
      }

      // Search a line item's children to find a matching ProductNumber
      public QuoteDetail FindChildItem(string strProductNumber)
      {
         string strTargetProductNumber = strProductNumber.ToUpper();
         QuoteDetail objMatchingItem = null;
         
         foreach (QuoteDetail item in this.QuoteOwner.LineItems)
         {
            if (item.ConfigParentId == this.QuoteDetailId)
            {
               if (item.ProductNumber.ToUpper() == strTargetProductNumber)
               {
                  objMatchingItem = item;
                  break;
               }
            }
         }        
         
         return objMatchingItem;
      }

      // Search a line item's children to find a matching product number and category
      public QuoteDetail FindChildItem(string strProductNumber, string strCategoryId)
      {
         string strTargetProductNumber = strProductNumber.ToUpper();
         QuoteDetail objMatchingItem = null;
         
         foreach (QuoteDetail item in this.QuoteOwner.LineItems)
         {
            if (item.ConfigParentId == this.QuoteDetailId)
            {
               if (item.ProductNumber.ToUpper() == strTargetProductNumber && item.CategoryId == strCategoryId)
               {
                  objMatchingItem = item;
                  break;
               }
            }
         }        
         
         return objMatchingItem;
      }

      // Search a line item's children to find all matching quote details
      public ArrayList FindChildItemList(string strProductNumber, string strCategoryId)
      {
         ArrayList objResultList = new ArrayList();
         string strTargetProductNumber = strProductNumber.ToUpper();
         
         foreach (QuoteDetail item in this.QuoteOwner.LineItems)
         {
            if (item.ConfigParentId == this.QuoteDetailId)
            {
               if (item.ProductNumber.ToUpper() == strTargetProductNumber && item.CategoryId == strCategoryId)
               {
                  objResultList.Add(item);
               }
            }
         }        
         
         return objResultList;
      }

      public void Init(Quote objQuote, QuoteDetail objParentItem, Product objProduct)
      {
         Init(objQuote, objProduct);
         this.ConfigParentId  = objParentItem.QuoteDetailId;
      }
      
      public void Init(Quote objQuote, Product objProduct)
      {
         m_objQuote = objQuote;
         this.UnitOfMeasureId = objProduct.DefaultUnitOfMeasureId;
         this.CategoryId = objProduct.CategoryId;
         this.AllowDiscounting = objProduct.AllowDiscounting;
         this.ConfigParentId = Guid.Empty;
         this.m_nLineItemNumber = 1;	
         this.m_strName = objProduct.Name;	
         this.m_guidQuoteId = m_objQuote.QuoteId;	
         this.m_nQuantity = 1;	
         this.m_guidProductId = objProduct.ProductId;	
         this.ProductNumber = objProduct.ProductNumber;
         this.m_nPricePerUnit = objProduct.Price;	         
         this.m_nManualDiscountAmount = 0;	         
      }

      public quotedetail CreateCrmObject()
      {
         quotedetail objNewObject = new quotedetail();   

         objNewObject.qadv_config_parent_id = this.ConfigParentId.ToString();
         objNewObject.qadv_config_category_id = this.CategoryId.ToString();
         objNewObject.qadv_allow_discounting = new CrmBoolean();
         objNewObject.qadv_allow_discounting.Value = this.AllowDiscounting;
         objNewObject.lineitemnumber = new CrmNumber();
         objNewObject.lineitemnumber.Value = this.LineItemNumber;
         
         if (this.ProductId == Guid.Empty)
         {
            objNewObject.productid = null;
         }
         else
         {
            objNewObject.productid = new Lookup();
            objNewObject.productid.Value = this.ProductId;
         }

         objNewObject.productdescription = this.ProductDescription;
         objNewObject.description = this.Name;

         objNewObject.priceperunit = new CrmMoney();
         objNewObject.priceperunit.Value = this.PricePerUnit;

         objNewObject.extendedamount = new CrmMoney();
         objNewObject.extendedamount.Value = this.ExtendedAmount;

         objNewObject.quantity = new CrmDecimal();
         objNewObject.quantity.Value = this.Quantity;

         objNewObject.quoteid = new Lookup();
         objNewObject.quoteid.Value = this.QuoteId;

         objNewObject.quotedetailid = new Key();
         objNewObject.quotedetailid.Value = this.QuoteDetailId;

         objNewObject.manualdiscountamount = new CrmMoney();
         objNewObject.manualdiscountamount.Value = this.ManualDiscountAmount;

         if (this.UnitOfMeasureId == Guid.Empty)
         {
            objNewObject.uomid = null;
         }
         else
         {
            objNewObject.uomid = new Lookup();
            objNewObject.uomid.Value = this.UnitOfMeasureId;
         }

         objNewObject.qadv_percentdiscount = GetCrmMoneyValue(this.PercentDiscount);
         objNewObject.qadv_percentmarkup = GetCrmMoneyValue(this.PercentMarkup);

         return objNewObject;
      }

      public void LoadFromCrmQuoteDetail(quotedetail objCrmQuoteDetail, Quote objQuote)
      {
         this.QuoteOwner = objQuote;

         if (objCrmQuoteDetail.qadv_config_parent_id == null)
         {
            this.ConfigParentId = Guid.Empty;
         }
         else
         {
            this.ConfigParentId = new Guid(objCrmQuoteDetail.qadv_config_parent_id);
         }

         if (objCrmQuoteDetail.qadv_config_category_id == null)
         {
            this.CategoryId = "";
         }
         else
         {
            this.CategoryId = objCrmQuoteDetail.qadv_config_category_id;
         }
   
         if (objCrmQuoteDetail.lineitemnumber == null)
         {
            this.LineItemNumber = 0;
         }
         else
         {
            this.LineItemNumber = objCrmQuoteDetail.lineitemnumber.Value;
         }

         if (objCrmQuoteDetail.qadv_allow_discounting == null)
         {
            this.AllowDiscounting = false;
         }
         else
         {
            this.AllowDiscounting = objCrmQuoteDetail.qadv_allow_discounting.Value;
         }

         if (objCrmQuoteDetail.productid == null)
         {
            this.ProductId = Guid.Empty;
         }
         else
         {
            this.ProductId = objCrmQuoteDetail.productid.Value;
         }

         this.ProductDescription = objCrmQuoteDetail.productdescription;
         this.PricePerUnit = objCrmQuoteDetail.priceperunit.Value;
         this.ExtendedAmount = objCrmQuoteDetail.extendedamount.Value;
         this.Quantity = objCrmQuoteDetail.quantity.Value;
         this.QuoteId = objCrmQuoteDetail.quoteid.Value;
         this.QuoteDetailId = objCrmQuoteDetail.quotedetailid.Value;

         this.ManualDiscountAmount = GetDecimalValue(objCrmQuoteDetail.manualdiscountamount);

         if (objCrmQuoteDetail.uomid == null)
         {
            this.UnitOfMeasureId = Guid.Empty;
         }
         else
         {
            this.UnitOfMeasureId = objCrmQuoteDetail.uomid.Value;
         }

         this.PercentDiscount = GetDecimalValue(objCrmQuoteDetail.qadv_percentdiscount);
         this.PercentMarkup = GetDecimalValue(objCrmQuoteDetail.qadv_percentmarkup);
      }
      
     
	} // end class
}
